#region Using References

using System;
using System.Collections.Generic;
using System.Linq;
using Ionic.Zip;

#endregion

namespace Beaker.Services.FileSystem.Zip
{
	internal class ZipFolderEntry
		: ZipFSEntry, IFolder
	{
		private readonly ZipFileSystemService _root;

		private readonly Dictionary<string, IFileSystemEntry> _entries
			= new Dictionary<string, IFileSystemEntry>( StringComparer.InvariantCultureIgnoreCase );

		public ZipFolderEntry( ZipFileSystemService root, IFolder parent, string folderName )
			: base( parent, folderName )
		{
			_root = root;
		}

		/// <summary>
		/// Gets the files in this folder.
		/// </summary>
		/// <returns>
		/// A sequence of files.
		/// </returns>
		public IEnumerable<IFile> GetFiles()
		{
			return _entries.Values.OfType<IFile>();
		}

		/// <summary>
		/// Gets the file with the given name.
		/// </summary>
		/// <param name="fileName">The name of the file to get.</param>
		/// <returns>The file with the given name, or <c>null</c> when it could not be found.</returns>
		public IFile GetFile( string fileName )
		{
			IFileSystemEntry entry;
			if( _entries.TryGetValue( fileName, out entry ) )
			{
				var file = entry as IFile;
				if( file != null )
					return file;
			}

			return null;
		}

		/// <summary>
		/// Gets the folders in this folder.
		/// </summary>
		/// <returns>
		/// A sequence of folders.
		/// </returns>
		public IEnumerable<IFolder> GetFolders()
		{
			return _entries.Values.OfType<IFolder>();
		}

		/// <summary>
		/// Gets the folder with the given name.
		/// </summary>
		/// <param name="folderName">The name of the folder to get.</param>
		/// <returns>The folder with the given name, or <c>null</c> when it could not be found.</returns>
		public IFolder GetFolder( string folderName )
		{
			IFileSystemEntry entry;
			if( _entries.TryGetValue( folderName, out entry ) )
			{
				var folder = entry as IFolder;
				if( folder != null )
					return folder;
			}

			return null;
		}

		/// <summary>
		/// Gets the entires in this folder.
		/// </summary>
		/// <returns>
		/// A sequence of items.
		/// </returns>
		public IEnumerable<IFileSystemEntry> GetEntries()
		{
			return _entries.Values;
		}

		/// <summary>
		/// Gets the entry with the given name in this folder.
		/// </summary>
		/// <param name="entryName">Name of the entry to get.</param>
		/// <returns>The entry with the given name, or <c>null</c> when it could not be found.</returns>
		public IFileSystemEntry GetEntry( string entryName )
		{
			IFileSystemEntry entry = null;
			_entries.TryGetValue( entryName, out entry );
			return entry;
		}

		internal IFolder GetOrCreateFolder( string folderName )
		{
			IFileSystemEntry entry = null;
			_entries.TryGetValue( folderName, out entry );

			IFolder folder = entry as IFolder;
			if( folder == null )
			{
				if( entry != null )
					throw new InvalidOperationException();

				folder = new ZipFolderEntry( _root, this, folderName );
				_entries.Add( folderName, folder );
			}

			return folder;
		}

		internal IFile GetOrCreateFile( ZipEntry entry, string fileName )
		{
			IFileSystemEntry baseEntry = null;
			_entries.TryGetValue( fileName, out baseEntry );

			IFile file = baseEntry as IFile;
			if( file == null )
			{
				if( baseEntry != null )
					throw new InvalidOperationException();

				file = new ZipFileEntry( _root, this, entry, fileName ).WrapIfProvided();
				_entries.Add( fileName, file );
			}

			return file;
		}
	}
}